package rmi;

import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.util.Date;

/**
 * @author REMY Timothée and CARTIER Arthur
 * 
 */
public class UserBuffer implements UserInterface {

	/**
	 * @author REMY Timothée and CARTIER Arthur
	 * 
	 */
	public class ConnectThisFriend implements Runnable {

		Me me;

		@Override
		public void run() {
			try {
				UserInterface thisFriend = null;
				if (getIp() != null && getIp().length() > 0 && getPort() > 0) {
					final ConnectionInterface distantConnection = (ConnectionInterface) Naming
							.lookup("//" + getIp() + ":" + getPort()
									+ "/connect");
					if (distantConnection != null) {
						thisFriend = distantConnection.connect(me,
								me.getConnection());
					}
				}
				if (thisFriend == null && getPseudo() != null
						&& getPseudo().length() > 0) {
					thisFriend = me.searchFriend(getPseudo(), 5);
				}
				if (thisFriend != null) {
					_setDistantUser(thisFriend);
				}
			} catch (final RemoteException e) {
				// this should not append on local object
			} catch (final MalformedURLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (final NotBoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

		}

	}

	UserInterface distantUser;
	private String pseudo;
	private String ip;
	private int port = 1099;
	private boolean isConnected;
	private Date lastUpdate;
	private Me me;

	public UserBuffer() {
		super();
	}

	public UserBuffer(final String pseudo) {
		super();
		this.pseudo = pseudo;
		isConnected = false;
	}

	public UserBuffer(final String pseudo, final String ip, final int port) {
		super();
		this.pseudo = pseudo;
		this.ip = ip;
		this.port = port;
		isConnected = false;
	}

	public UserBuffer(final String pseudo, final String ip, final int port,
			final Date lastUpdate, final Me me) {
		super();
		this.pseudo = pseudo;
		this.ip = ip;
		this.port = port;
		this.lastUpdate = lastUpdate;
		isConnected = false;
		this.me = me;
	}

	public UserBuffer(final UserInterface newConnectedFriend, final Me me)
			throws RemoteException {
		super();
		distantUser = newConnectedFriend;
		isConnected = true;
		this.me = me;
		refresh();
	}

	/**
	 * @param isConnected
	 *            the isConnected to set
	 */
	public void _setConnected(final boolean isConnected) {
		this.isConnected = isConnected;
	}

	/**
	 * @throws RemoteException
	 * 
	 */
	public void _setDistantUser(final UserInterface distantUser)
			throws RemoteException {
		this.distantUser = distantUser;
		if (distantUser != null) {
			isConnected = true;
			refresh();
		}
	}

	/**
	 * @see rmi.UserInterface#disconnect()
	 * @throws RemoteException
	 */
	@Override
	public void disconnect(final String pseudo) throws RemoteException {
		if (distantUser != null) {
			distantUser.disconnect(pseudo);
		}

	}

	/**
	 * @return the distantUser
	 */
	public UserInterface getDistantUser() {
		return distantUser;
	}

	/**
	 * @see rmi.UserInterface#getIp()
	 * @return
	 * @throws RemoteException
	 */
	@Override
	public String getIp() throws RemoteException {
		if (isConnected
				&& ((new Date()).getTime() - lastUpdate.getTime()) > 12000) {
			refresh();
		}
		return ip;
	}

	/**
	 * @return the lastUpdate
	 */
	public Date getLastUpdate() {
		return lastUpdate;
	}

	/**
	 * @return the me
	 */
	public Me getMe() {
		return me;
	}

	/**
	 * @see rmi.UserInterface#getPort()
	 * @return
	 * @throws RemoteException
	 */
	@Override
	public int getPort() throws RemoteException {
		if (isConnected
				&& ((new Date()).getTime() - lastUpdate.getTime()) > 12000) {
			refresh();
		}
		return port;
	}

	/**
	 * @see rmi.UserInterface#getPseudo()
	 * @return
	 * @throws RemoteException
	 */
	@Override
	public String getPseudo() throws RemoteException {
		if (isConnected
				&& ((new Date()).getTime() - lastUpdate.getTime()) > 12000) {
			refresh();
		}
		return pseudo;
	}

	/**
	 * @see rmi.UserInterface#initDiscussion(rmi.DiscussionInterface)
	 * @param newDiscussion
	 * @return
	 * @throws RemoteException
	 */
	@Override
	public boolean initDiscussion(final DiscussionInterface newDiscussion)
			throws RemoteException {
		return distantUser.initDiscussion(newDiscussion);
	}

	/**
	 * @return the isConnected
	 */
	public boolean isConnected() {
		return isConnected;
	}

	public void refresh() throws RemoteException {
		if (isConnected && distantUser != null) {
			try {
				ip = distantUser.getIp();
				port = distantUser.getPort();
				final String temp = distantUser.getPseudo();
				if (!temp.equals(pseudo)) {
					me.getFriends().remove(pseudo);
					pseudo = temp;
					me.getFriends().put(temp, this);
				}
			} catch (final RemoteException e) {
				isConnected = false;
				throw e;
			}
		}
		lastUpdate = new Date();
	}

	/**
	 * @see rmi.UserInterface#searchFriend(java.lang.String, int)
	 * @param pseudo
	 * @param ttl
	 * @return
	 * @throws RemoteException
	 */
	@Override
	public UserInterface searchFriend(final String pseudo, final int ttl)
			throws RemoteException {
		return distantUser.searchFriend(pseudo, ttl);
	}

	/**
	 * @param ip
	 *            the ip to set
	 */
	public void setIp(final String ip) {
		this.ip = ip;
	}

	/**
	 * @param lastUpdate
	 *            the lastUpdate to set
	 */
	public void setLastUpdate(final Date lastUpdate) {
		this.lastUpdate = lastUpdate;
	}

	/**
	 * @param me
	 *            the me to set
	 */
	public void setMe(final Me me) {
		this.me = me;
	}

	/**
	 * @param port
	 *            the port to set
	 */
	public void setPort(final int port) {
		this.port = port;
	}

	/**
	 * @param pseudo
	 *            the pseudo to set
	 */
	public void setPseudo(final String pseudo) {
		this.pseudo = pseudo;
	}

	/**
	 * @see java.lang.Object#toString()
	 * @return
	 */
	@Override
	public String toString() {
		if (isConnected) {
			return pseudo + " (connecté)";
		} else {
			return pseudo + " (déconnecté)";
		}
	}

}
